package com.jl15988.simpletools.common.aop;

import cn.hutool.json.JSONUtil;
import com.jl15988.simpletools.common.annotation.Log;
import com.jl15988.simpletools.system.domain.entity.User;
import com.jl15988.simpletools.system.service.OperationLogService;
import com.jl15988.simpletools.system.service.UserService;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.servlet.http.HttpServletRequest;
import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.Map;

/**
 * 操作日志切面
 *
 * @author jl15988
 */
@Slf4j
@Aspect
@Component
public class LogAspect {

    @Autowired
    private UserService userService;

    @Autowired
    private OperationLogService operationLogService;

    /**
     * 配置切入点
     */
    @Pointcut("@annotation(com.jl15988.simpletools.common.annotation.Log)")
    public void logPointCut() {
    }

    /**
     * 处理完请求后执行
     *
     * @param joinPoint 切点
     * @param result    返回值
     */
    @AfterReturning(pointcut = "logPointCut()", returning = "result")
    public void doAfterReturning(JoinPoint joinPoint, Object result) {
        handleLog(joinPoint, result);
    }

    /**
     * 处理日志
     *
     * @param joinPoint 切点
     * @param result    返回值
     */
    private void handleLog(JoinPoint joinPoint, Object result) {
        try {
            // 获取当前用户
            User currentUser = userService.getCurrentUser();
            if (currentUser == null) {
                return;
            }

            // 获取请求信息
            ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
            if (attributes == null) {
                return;
            }
            HttpServletRequest request = attributes.getRequest();

            // 获取注解信息
            Log logAnnotation = getLogAnnotation(joinPoint);
            if (logAnnotation == null) {
                return;
            }

            // 构建日志信息
            Map<String, Object> logInfo = new HashMap<>(8);
            logInfo.put("userId", currentUser.getId());
            logInfo.put("username", currentUser.getUsername());
            logInfo.put("operationType", logAnnotation.operationType().name());
            logInfo.put("title", logAnnotation.title());
            logInfo.put("method", request.getMethod());
            logInfo.put("url", request.getRequestURI());
            logInfo.put("ip", getIpAddress(request));
            logInfo.put("result", result);

            // 记录日志
            log.info("操作日志: {}", JSONUtil.toJsonStr(logInfo));

            // 保存日志到数据库
            operationLogService.addLog(
                    currentUser.getId(),
                    logAnnotation.operationType().name(),
                    null, // 目标ID，可以根据实际情况从请求参数中获取
                    JSONUtil.toJsonStr(logInfo)
            );
        } catch (Exception e) {
            log.error("记录操作日志异常", e);
        }
    }

    /**
     * 获取注解信息
     *
     * @param joinPoint 切点
     * @return 注解信息
     */
    private Log getLogAnnotation(JoinPoint joinPoint) {
        MethodSignature signature = (MethodSignature) joinPoint.getSignature();
        Method method = signature.getMethod();
        return method.getAnnotation(Log.class);
    }

    /**
     * 获取IP地址
     *
     * @param request 请求
     * @return IP地址
     */
    private String getIpAddress(HttpServletRequest request) {
        String ip = request.getHeader("x-forwarded-for");
        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getHeader("Proxy-Client-IP");
        }
        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getHeader("WL-Proxy-Client-IP");
        }
        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getRemoteAddr();
        }
        return ip;
    }
} 